using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace OpenComposite.Base.Designer
{
	public class Symbol : DesignerControl, IConnector, IConnectorFactory
	{

		#region Initialization
		public Symbol()
		{
			init();
		}
		private void init()
		{
			this.BeginUpdate();

			//
			// _borderPen
			//
			_borderPen = new Pen(Color.Blue);

			//
			// _textbox
			//
			_textbox = new TextBox();
			_textbox.Bounds = new Rectangle(0, 0, this.ClientRectangle.Width, 15);
			_textbox.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
			_textbox.TextChanged += new EventHandler(_textbox_TextChanged);

			_borderPath = new GraphicsPath();
			_customPath = null;

			this.MinimumSize = new Size(20, 20);

			//this.Name = "symbol" + GetCount(typeof(Symbol));
			this.Text = this.Name;

			this.BackColor2 = Color.White;
			this.BackgroundImage = null;
			this.BackgroundImageLayout = ImageLayout.Tile;

			this.AutoSize = false;

			this.Border = BorderType.Rectangle;
			this.BorderColor = Color.Blue;
			this.BorderStyle = DashStyle.Solid;
			this.BorderWidth = 3;

			this.Controls.Add(_textbox);

			this.EndUpdate();
		}

		#endregion

		#region Public Members

		#region Properties

		public bool AutoSize
		{
			get
			{
				return _bAutoSize;
			}
			set
			{
				bool changed = ( _bAutoSize != value );
				_bAutoSize = value;
				if ( changed )
					doAutoSizeChanged();
			}
		}

		public BackgroundBrushMode BackBrushMode
		{
			get { return _backgroudBrushMode; }
			set
			{
				if ( _backgroudBrushMode != value ) {
					_backgroudBrushMode = value;
					setBackgroundBrush();
				}
			}
		}
		public Color BackColor2
		{
			get
			{
				return _backColor2;
			}
			set
			{
				if ( _backColor2 != value ) {
					_backColor2 = value;
					doBackColor2Changed();
				}
			}
		}
		public LinearGradientMode BackLinearGradientMode
		{
			get { return _backLinearGradientMode; }
			set
			{
				if ( _backLinearGradientMode != value ) {
					_backLinearGradientMode = value;
					setBackgroundBrush();
				}
			}
		}
		public HatchStyle BackHatchStyle
		{
			get { return _backHatchStyle; }
			set
			{
				if ( _backHatchStyle != value ) {
					_backHatchStyle = value;
					setBackgroundBrush();
				}
			}
		}

		public Rectangle TextRectangle {
			get { return _textRectangle; }
			set {
				if ( _textRectangle != value ) {
					_textRectangle = value;
					doTextRectangleChanged();
				}
			}
		}
		public ContentAlignment TextAlign
		{
			get { return _textAlign; }
			set
			{
				bool changed = ( _textAlign != value );
				_textAlign = value;
				if ( changed )
					doTextAlignChanged();
			}
		}

		public Image BackgroundImage
		{
			get
			{
				return _backImage;
			}
			set
			{
				_backImage = value;
				Repaint();
			}
		}
		public ImageLayout BackgroundImageLayout
		{
			get
			{
				return _backImageLayout;
			}
			set
			{
				_backImageLayout = value;
				Repaint();
			}
		}

		public BorderType Border
		{
			get { return _borderType; }
			set
			{
				if ( _borderType != value ) {
					_borderType = value;
					doBorderTypeChanged();
				}
			}
		}
		public DashStyle BorderStyle
		{
			get
			{
				if ( _borderPen == null )
					_borderPen = new Pen(Color.Blue, 3.0f);
				return _borderPen.DashStyle;
			}
			set
			{
				if ( _borderPen.DashStyle != value ) {
					_borderPen.DashStyle = value;
					doBorderPenChanged();
				}
			}
		}
		public Color BorderColor
		{
			get
			{
				if ( _borderPen == null )
					_borderPen = new Pen(Color.Blue, 3.0f);
				return _borderPen.Color;
			}
			set
			{
				if ( _borderPen.Color != value ) {
					_borderPen.Color = value;
					doBorderPenChanged();
				}
			}
		}
		public int BorderWidth
		{
			get
			{
				if ( _borderPen == null )
					_borderPen = new Pen(Color.Blue, 3.0f);
				return (int)_borderPen.Width;
			}
			set
			{
				if ( _borderPen.Width != value ) {
					_borderPen.Width = value;
					doBorderPenChanged();
				}
			}
		}
		public int BorderFixedRoundedBorderDiameter
		{
			get { return _roundRectDiameter; }
			set
			{
				if ( _roundRectDiameter != value ) {
					_roundRectDiameter = value;
					doBorderFixedRoundedBorderDiameterChanged();
				}
			}
		}
		[XmlIgnore]
		public GraphicsPath BorderPath
		{
			get { return _borderPath; }
			set
			{
				_customPath = value;
			}
		}

		#endregion

		#region Events
		#endregion

		#region Methods
		#endregion

		#region Override

		public override string Text
		{
			get
			{
				return _textbox.Text;
			}
			set
			{
				_textbox.Text = value;
			}
		}

		public override bool CanFocused
		{
			get { return true; }
		}
		public override bool CanMove
		{
			get { return true; }
		}
		public override bool CanSelect
		{
			get { return true; }
		}
		public override bool CanResize
		{
			get { return true; }
		}
		public override bool IsContainer
		{
			get { return false; }
		}
		public override bool UseGrid
		{
			get
			{
				return true;
			}
		}

		public override void Dispose()
		{
			try {
				dispose(_backImage);
				dispose(_borderPath);
				dispose(_borderPen);

				base.Dispose();
			} finally {
			}
		}
		
		public override void PaintBackground(PaintEventArgs pe)
		{
			base.PaintBackground(pe);

			Rectangle rectPaint = GetPaintBounds();
			if ( this.BorderPath != null && this.BorderPath.PointCount > 0 ) {
				using ( GraphicsPath border = (GraphicsPath)this.BorderPath.Clone() ) {
					// move to the defined location
					if ( border.PointCount > 0 ) {
						Matrix m = new Matrix();
						m.Translate(rectPaint.X, rectPaint.Y);
						border.Transform(m);

						// draw border
						if ( this.Border != BorderType.None ) {
							pe.Graphics.DrawPath(( this.Enabled ? this.BorderPen : Pens.LightGray ), border);
						}
						// fill client area
						if ( this.BackBrush != null && this.BackColor != Color.Transparent ) {
							//Region r = new Region(border);
							//r.Intersect(pe.Graphics.Clip);
							pe.Graphics.FillPath(( this.Enabled ? this.BackBrush : Brushes.WhiteSmoke ), border);
							//pe.Graphics.FillRegion(( this.Enabled ? this.BackBrush : Brushes.WhiteSmoke ), r);
						}
					}
				}
			} else {
				if ( this.BackBrush != null && this.BackColor != Color.Transparent )
					pe.Graphics.FillRectangle(( this.Enabled ? this.BackBrush : SystemBrushes.Control ),
											  rectPaint);
			}
		}
		public override void Paint(PaintEventArgs pe)
		{			
			base.Paint(pe);
		}

		#endregion

		#region IConnectorFactory Members
		public virtual bool CreateRouteStart(DesignerControl controlEnd,
			out IConnector connector, out LineCap cap, out CustomLineCap customcap,
			out RouteDockDirection dockStart, out RouteDockDirection dockEnd, out bool useStartConnectorAsRouteStart)
		{
			Rectangle rS = this.GetPaintBounds();
			Rectangle rE = controlEnd.GetPaintBounds();
			CalculateRouteDockDirection(rS, rE, out dockStart, out dockEnd);
			connector = this;
			cap = LineCap.NoAnchor;
			customcap = null;
			useStartConnectorAsRouteStart = false;
			return true;
		}
		public virtual bool CreateRouteEnd(DesignerControl controlStart,
			out IConnector connector, out LineCap cap, out CustomLineCap customcap,
			out RouteDockDirection dockStart, out RouteDockDirection dockEnd, out bool useEndConnectorAsRouteEnd)
		{
			Rectangle rS = controlStart.GetPaintBounds();
			Rectangle rE = this.GetPaintBounds();
			CalculateRouteDockDirection(rS, rE, out dockStart, out dockEnd);
			connector = this;
			cap = LineCap.Custom;
			customcap = new AdjustableArrowCap(5.0f, 5.0f, true);
			useEndConnectorAsRouteEnd = false;
			return true;
		}
		#endregion
		#region IConnector Members

		public virtual Point GetRouteStart(RouteDockDirection dock, Route route)
		{
			return getDefaultDockPoint(dock);
		}
		public virtual Point GetRouteEnd(RouteDockDirection dock, Route route)
		{
			return getDefaultDockPoint(dock);
		}

		#endregion

		#endregion

		#region Protected Members

		#region Properties

		protected override Brush BackBrush
		{
			get
			{
				return _backCurrentBrush;
			}
		}

		protected Pen BorderPen
		{
			get { return _borderPen; }
		}
		
		protected TextBox NameTextBox
		{
			get { return _textbox; }
		}

		#endregion

		#region Methods

		protected override void OnMouseMove(MouseEventArgs e)
		{
			base.OnMouseMove(e);
			//if ( this.DesignerViewControl.Status.MouseOverCtrl == this ) {
			//    Rectangle rt = this.TextRectangle;
			//    if ( Parent != null )
			//        rt = this.Parent.RectangleToDesignerView(rt);

			//    if ( rt.Contains(e.Location) )
			//        this.DesignerViewControl.Cursor = Cursors.IBeam;
			//    else if ( this.DesignerViewControl.Cursor == Cursors.IBeam )
			//        this.DesignerViewControl.Cursor = this.Cursor;
			//}
		}

		protected override void OnLocationChanged(EventArgs e)
		{
			if ( this.BackBrushMode == BackgroundBrushMode.LinearGradient ||
				 this.BackBrushMode == BackgroundBrushMode.PathGradient ) {
				setBackgroundBrush();
			}
			base.OnLocationChanged(e);
		}
		protected override void OnSizeChanged(EventArgs e)
		{
			createBorder();
			//_textRectangle.Size = new Size(this.Width, this.Height);
			if ( this.BackBrushMode == BackgroundBrushMode.LinearGradient ||
				 this.BackBrushMode == BackgroundBrushMode.PathGradient ) {
				setBackgroundBrush();
			}
			base.OnSizeChanged(e);
		}
		protected override void OnParentChanged(EventArgs e)
		{
			setBackgroundBrush();
			base.OnParentChanged(e);
		}
		protected override void OnParentLocationChanged()
		{
			setBackgroundBrush();
			base.OnParentLocationChanged();
		}
		protected override void OnParentSizeChanged()
		{
			setBackgroundBrush();
			base.OnParentSizeChanged();
		}

		protected override void OnBackColorChanged(EventArgs e)
		{
			setBackgroundBrush();
			base.OnBackColorChanged(e);
		}

		protected override Rectangle CalculateClientArea()
		{
			Rectangle rc = this.Bounds;
			rc.Inflate(-5, -5);
			return rc;
		}

		protected virtual Rectangle CalculateTextArea(Graphics g)
		{
			Rectangle r = CalculateClientArea();
			SizeF size = g.MeasureString(this.Text, this.Font, r.Size, _textFormat);
			if ( _textFormat.LineAlignment == StringAlignment.Far ) {
				// bottom
				r.Y = (int)(r.Bottom - size.Height);
				r.Height = (int)size.Height;
			} else if ( _textFormat.LineAlignment == StringAlignment.Center ) {
				// center
				r.Y = (int)(r.Top + ( r.Height / 2 ) - ( size.Height / 2 ));
				r.Height = (int)size.Height;
			} else if ( _textFormat.LineAlignment == StringAlignment.Near ) {
				// top
				r.Height = (int)size.Height;
			}
			return r;
		}

		protected virtual void CalculateBorder(int width, int height, ref GraphicsPath path)
		{
			path.AddPolygon(
				new Point[] {
					new Point(0,0),
					new Point(width/2,height/4),
					new Point(width,0),
					new Point((width*3)/4,height/2),
					new Point(width,height),
					new Point(width/2,(height*3)/4),
					new Point(0,height),
					new Point(width/4,height/2)
				}
			);
		}
		
		protected void CalculateRouteDockDirection(Rectangle rStart, Rectangle rEnd,
			out RouteDockDirection dockStart, out RouteDockDirection dockEnd)
		{
			dockStart = RouteDockDirection.Right;
			dockEnd = RouteDockDirection.Left;
			try {
				int x1 = rStart.X, y1 = rStart.Y, h1 = rStart.Height, w1 = rStart.Width;
				int x2 = rEnd.X, y2 = rEnd.Y, h2 = rEnd.Height, w2 = rEnd.Width;
				int dx = 30, dy = 30;

				// t1    |     | dx |
				// ------|-----|----|------
				// t2    |    _|_   |  dy
				// ------|---|_1_|h1|------     
				// t3    |     w1   |
				// ------|-----|----|------
				// t4    |     |    |
				//    l1 | l2  | l3 | l4
				bool t1 = ( y2 + h2 + dy < y1 );
				bool t4 = ( y2 > y1 + h1 + dy );
				bool t2 = !t1 && ( y2 + h2 < y1 + h1 / 2 );
				bool t3 = !t4 && ( y2 > y1 + h1 / 2 );
				bool l1 = ( x2 + w2 + dx < x1 );
				bool l4 = ( x2 > x1 + w1 + dx );
				bool l2 = !l1 && ( x2 + w2 < x1 + w1 / 2 );
				bool l3 = !l4 && ( x2 > x1 + w1 / 2 );

				if ( l1 ) {
					dockStart = RouteDockDirection.Left;
					dockEnd = RouteDockDirection.Right;
				} else if ( l4 ) {
					dockStart = RouteDockDirection.Right;
					dockEnd = RouteDockDirection.Left;
				} else if ( t1 ) {
					dockStart = RouteDockDirection.Top;
					dockEnd = RouteDockDirection.Bottom;
				} else if ( t4 ) {
					dockStart = RouteDockDirection.Bottom;
					dockEnd = RouteDockDirection.Top;
				} else if ( t2 && l2 ) {
					dockStart = RouteDockDirection.Left;
					dockEnd = RouteDockDirection.Bottom;
				} else if ( t3 && l2 ) {
					dockStart = RouteDockDirection.Left;
					dockEnd = RouteDockDirection.Top;
				} else if ( t3 && l3 ) {
					dockStart = RouteDockDirection.Right;
					dockEnd = RouteDockDirection.Top;
				} else if ( t2 && l3 ) {
					dockStart = RouteDockDirection.Right;
					dockEnd = RouteDockDirection.Bottom;
				}
			} catch { }
		}

		protected override void CalculateSpecialBounds()
		{
			base.CalculateSpecialBounds();
			setBackgroundBrush();
		}
		#endregion

		#endregion

		#region Private Members

		#region Variables

		private bool _bAutoSize;

		private int _roundRectDiameter = 10;

		private Color _backColor2;
		private Pen _borderPen;

		private BackgroundBrushMode _backgroudBrushMode;
		private volatile Brush _backCurrentBrush;

		private LinearGradientMode _backLinearGradientMode;
		private HatchStyle _backHatchStyle;

		private Rectangle _textRectangle;
		private ContentAlignment _textAlign;
		private StringFormat _textFormat;

		private volatile Image _backImage;
		private ImageLayout _backImageLayout;

		private volatile GraphicsPath _borderPath;
		private volatile GraphicsPath _customPath;
		private volatile BorderType _borderType;

		private volatile TextBox _textbox;

		#endregion

		#region Methods
		private void doAutoSizeChanged()
		{
			doBorderTypeChanged();
			Repaint();
		}
		private void doBackColor2Changed()
		{
			setBackgroundBrush();
			Invalidate();
			Update();
		}
		private void doTextAlignChanged()
		{
			if ( _textFormat == null )
				_textFormat = new StringFormat();
			switch ( _textAlign ) {
				case ContentAlignment.BottomCenter:
					_textbox.TextAlign = HorizontalAlignment.Center;
					_textFormat.LineAlignment = StringAlignment.Far;
					_textFormat.Alignment = StringAlignment.Center;
					break;
				case ContentAlignment.BottomLeft:
					_textbox.TextAlign = HorizontalAlignment.Left;
					_textFormat.LineAlignment = StringAlignment.Far;
					_textFormat.Alignment = StringAlignment.Near;
					break;
				case ContentAlignment.BottomRight:
					_textbox.TextAlign = HorizontalAlignment.Right;
					_textFormat.LineAlignment = StringAlignment.Far;
					_textFormat.Alignment = StringAlignment.Far;
					break;
				case ContentAlignment.MiddleCenter:
					_textbox.TextAlign = HorizontalAlignment.Center;
					_textFormat.LineAlignment = StringAlignment.Center;
					_textFormat.Alignment = StringAlignment.Center;
					break;
				case ContentAlignment.MiddleLeft:
					_textbox.TextAlign = HorizontalAlignment.Left;
					_textFormat.LineAlignment = StringAlignment.Center;
					_textFormat.Alignment = StringAlignment.Near;
					break;
				case ContentAlignment.MiddleRight:
					_textbox.TextAlign = HorizontalAlignment.Right;
					_textFormat.LineAlignment = StringAlignment.Center;
					_textFormat.Alignment = StringAlignment.Far;
					break;
				case ContentAlignment.TopCenter:
					_textbox.TextAlign = HorizontalAlignment.Center;
					_textFormat.LineAlignment = StringAlignment.Near;
					_textFormat.Alignment = StringAlignment.Center;
					break;
				case ContentAlignment.TopLeft:
					_textbox.TextAlign = HorizontalAlignment.Left;
					_textFormat.LineAlignment = StringAlignment.Near;
					_textFormat.Alignment = StringAlignment.Near;
					break;
				case ContentAlignment.TopRight:
					_textbox.TextAlign = HorizontalAlignment.Right;
					_textFormat.LineAlignment = StringAlignment.Near;
					_textFormat.Alignment = StringAlignment.Far;
					break;
				default:
					break;
			}
		}
		private void doTextRectangleChanged()
		{
			Repaint();
		}
		private void doBorderPenChanged()
		{
			Repaint();
		}
		private void doBorderTypeChanged()
		{
			createBorder();
			Repaint();
		}
		private void doBorderFixedRoundedBorderDiameterChanged()
		{
			createBorder();
			Repaint();
		}
		/// <summary>
		/// Create new border path.
		/// </summary>
		private void createBorder()
		{
			BorderType type = this.Border;
			int width = this.Width;
			int height = this.Height;
			int dia = this.BorderFixedRoundedBorderDiameter;
			
			_borderPath.Reset();

			switch ( type ) {
				#region case BorderType.CustomPolygon:
				case BorderType.CustomPolygon:
					GraphicsPath path = new GraphicsPath();
					CalculateBorder(width, height, ref path);
					_borderPath.AddPath(path, true);
					break;
				#endregion
				#region case BorderType.Diamond:
				case BorderType.Diamond:
					_borderPath.AddPolygon(new Point[]{ 
								new Point(0,height/2),
						        new Point(width/2,0),
						        new Point(width,height/2),
						        new Point(width/2,height)
												  });
					break;
				#endregion
				#region case BorderType.Rectangle:
				case BorderType.Rectangle:
					_borderPath.AddRectangle(new Rectangle(0, 0, width, height));
					break;
				#endregion
				#region case BorderType.Ellipse:
				case BorderType.Ellipse:
					_borderPath.AddEllipse(0, 0, width, height);
					break;
				#endregion
				#region case BorderType.TriangleUp:
				case BorderType.TriangleUp:
					_borderPath.AddPolygon(new Point[] { new Point(0, height), new Point(width, height), new Point(width / 2, 0) });
					break;
				#endregion
				#region case BorderType.TriangleDown:
				case BorderType.TriangleDown:
					_borderPath.AddPolygon(new Point[] { new Point(0, 0), new Point(width, 0), new Point(width / 2, height) });
					break;
				#endregion
				#region case BorderType.TriangleLeft:
				case BorderType.TriangleLeft:
					_borderPath.AddPolygon(new Point[] { new Point(width, 0), new Point(0, height / 2), new Point(width, height) });
					break;
				#endregion
				#region case BorderType.TriangleRight:
				case BorderType.TriangleRight:
					_borderPath.AddPolygon(new Point[] { new Point(0, 0), new Point(width, height / 2), new Point(0, height) });
					break;
				#endregion
				#region case BorderType.RoundedRectangle:
				case BorderType.RoundedRectangle:
					_borderPath.AddArc(0, 0, dia, dia, 180, 90);
					_borderPath.AddArc(width - dia, 0, dia, dia, 270, 90);
					_borderPath.AddArc(width - dia, height - dia, dia, dia, 0, 90);
					_borderPath.AddArc(0, height - dia, dia, dia, 90, 90);
					_borderPath.CloseAllFigures();
					break;
				#endregion
				#region case BorderType.DynamicRoundedRectangle:
				case BorderType.DynamicRoundedRectangle:
					dia = width / 5;
					_borderPath.AddArc(0, 0, dia, dia, 180, 90);
					_borderPath.AddArc(width - dia, 0, dia, dia, 270, 90);
					_borderPath.AddArc(width - dia, height - dia, dia, dia, 0, 90);
					_borderPath.AddArc(0, height - dia, dia, dia, 90, 90);
					_borderPath.CloseAllFigures();
					break;
				#endregion
				#region case BorderType.BallonSW:
				case BorderType.BallonSW:
					_borderPath.AddArc(0, 0, width / 4, width / 4, 180, 90);
					_borderPath.AddLine(width / 8, 0, width - width / 8, 0);
					_borderPath.AddArc(width - width / 4, 0, width / 4, width / 4, 270, 90);
					_borderPath.AddLine(width, width / 8, width, ( height * 0.75f ) - width / 8);
					_borderPath.AddArc(width - width / 4, ( height * 0.75f ) - width / 4, width / 4, width / 4, 0, 90);
					_borderPath.AddLine(width - width / 8, ( height * 0.75f ), width / 8 + ( width / 4 ), ( height * 0.75f ));
					_borderPath.AddLine(width / 8 + ( width / 4 ), height * 0.75f, width / 8 + ( width / 8 ), height);
					_borderPath.AddLine(width / 8 + ( width / 8 ), height, width / 8 + ( width / 8 ), ( height * 0.75f ));
					_borderPath.AddLine(width / 8 + ( width / 8 ), ( height * 0.75f ), width / 8, ( height * 0.75f ));
					_borderPath.AddArc(0, ( height * 0.75f ) - width / 4, width / 4, width / 4, 90, 90);
					_borderPath.AddLine(0, ( height * 0.75f ) - width / 8, 0, width / 8);
					break;
				#endregion
				#region case BorderType.BallonSE:
				case BorderType.BallonSE:
					_borderPath.AddArc(0, 0, width / 4, width / 4, 180, 90);
					_borderPath.AddLine(width / 8, 0, width - width / 8, 0);
					_borderPath.AddArc(width - width / 4, 0, width / 4, width / 4, 270, 90);
					_borderPath.AddLine(width, width / 8, width, ( height * 0.75f ) - width / 8);
					_borderPath.AddArc(width - width / 4, ( height * 0.75f ) - width / 4, width / 4, width / 4, 0, 90);
					_borderPath.AddLine(width - width / 8, ( height * 0.75f ), width - ( width / 4 ), ( height * 0.75f ));
					_borderPath.AddLine(width - ( width / 4 ), height * 0.75f, width - ( width / 4 ), height);
					_borderPath.AddLine(width - ( width / 4 ), height, width - ( 3 * width / 8 ), ( height * 0.75f ));
					_borderPath.AddLine(width - ( 3 * width / 8 ), ( height * 0.75f ), width / 8, ( height * 0.75f ));
					_borderPath.AddArc(0, ( height * 0.75f ) - width / 4, width / 4, width / 4, 90, 90);
					_borderPath.AddLine(0, ( height * 0.75f ) - width / 8, 0, width / 8);
					break;
				#endregion
				#region case BorderType.BallonNW:
				case BorderType.BallonNW:
					_borderPath.AddArc(width - width / 4, ( height ) - width / 4, width / 4, width / 4, 0, 90);
					_borderPath.AddLine(width - width / 8, ( height ), width - ( width / 4 ), ( height ));
					_borderPath.AddArc(0, ( height ) - width / 4, width / 4, width / 4, 90, 90);
					_borderPath.AddLine(0, ( height ) - width / 8, 0, height * 0.25f + width / 8);
					_borderPath.AddArc(0, height * 0.25f, width / 4, width / 4, 180, 90);
					_borderPath.AddLine(width / 8, height * 0.25f, width / 4, height * 0.25f);
					_borderPath.AddLine(width / 4, height * 0.25f, width / 4, 0);
					_borderPath.AddLine(width / 4, 0, 3 * width / 8, height * 0.25f);
					_borderPath.AddLine(3 * width / 8, height * 0.25f, width - width / 8, height * 0.25f);
					_borderPath.AddArc(width - width / 4, height * 0.25f, width / 4, width / 4, 270, 90);
					_borderPath.AddLine(width, width / 8 + height * 0.25f, width, ( height ) - width / 8);
					break;
				#endregion
				#region case BorderType.BallonNE:
				case BorderType.BallonNE:
					_borderPath.AddArc(width - width / 4, ( height ) - width / 4, width / 4, width / 4, 0, 90);
					_borderPath.AddLine(width - width / 8, ( height ), width - ( width / 4 ), ( height ));
					_borderPath.AddArc(0, ( height ) - width / 4, width / 4, width / 4, 90, 90);
					_borderPath.AddLine(0, ( height ) - width / 8, 0, height * 0.25f + width / 8);
					_borderPath.AddArc(0, height * 0.25f, width / 4, width / 4, 180, 90);
					_borderPath.AddLine(width / 8, height * 0.25f, 5 * width / 8, height * 0.25f);
					_borderPath.AddLine(5 * width / 8, height * 0.25f, 3 * width / 4, 0);
					_borderPath.AddLine(3 * width / 4, 0, 3 * width / 4, height * 0.25f);
					_borderPath.AddLine(3 * width / 4, height * 0.25f, width - width / 8, height * 0.25f);
					_borderPath.AddArc(width - width / 4, height * 0.25f, width / 4, width / 4, 270, 90);
					_borderPath.AddLine(width, width / 8 + height * 0.25f, width, ( height ) - width / 8);
					break;
				#endregion
				case BorderType.SimpleArrowUp:
					_borderPath.AddPolygon(new Point[] {
						new Point(0, (int)( height * .25f )),
						new Point((int)(width * .5f), 0),
						new Point(width, (int)( height * .25f )),
						new Point(width, height),
						new Point((int)( width * .5f ), (int)(height * .75f)),
						new Point(0, height)
					});
					break;
				case BorderType.SimpleArrowDown:
					_borderPath.AddPolygon(new Point[] {
						new Point(0, 0),
						new Point((int)(width * .5f), (int)( height * .25f )),
						new Point(width, 0),
						new Point(width, (int)(height * .75f)),
						new Point((int)( width * .5f ), height),
						new Point(0, (int)(height * .75f))
					});
					break;
				case BorderType.SimpleArrowLeft:
					_borderPath.AddPolygon(new Point[] {
						new Point((int)( width * .25f ), 0),
						new Point(width, 0),
						new Point((int)( width * .75f ), (int)( height * .5f )),
						new Point(width, height),
						new Point((int)( width * .25f ), height),
						new Point(0, (int)( height * .5f ))
					});
					break;
				case BorderType.SimpleArrowRight:
					_borderPath.AddPolygon(new Point[] {
						new Point(0, 0),
						new Point((int)( width * .75f ), 0),
						new Point(width, (int)( height * .5f )),
						new Point((int)( width * .75f ), height),
						new Point(0, height),
						new Point((int)( width * .25f ), (int)( height * .5f ))
					});
					break;
			}
		}

		private void doBackBrushModeChanged()
		{
			setBackgroundBrush();
			Invalidate();
			Update();
		}

		private Point getDefaultDockPoint(RouteDockDirection dock)
		{
			Rectangle bounds = this.GetPaintBounds();
			Point p = new Point();
			switch ( dock ) {
				case RouteDockDirection.Top:
					p.X = bounds.Left + ( ( bounds.Right - bounds.Left ) / 2 );
					p.Y = bounds.Top;
					break;
				case RouteDockDirection.Bottom:
					p.X = bounds.Left + ( ( bounds.Right - bounds.Left ) / 2 );
					p.Y = bounds.Bottom;
					break;
				case RouteDockDirection.Right:
					p.X = bounds.Right;
					p.Y = bounds.Top + ( ( bounds.Bottom - bounds.Top ) / 2 );
					break;
				case RouteDockDirection.Left:
					p.X = bounds.Left;
					p.Y = bounds.Top + ( ( bounds.Bottom - bounds.Top ) / 2 );
					break;
			}
			return p;
		}

		private void setBackgroundBrush()
		{
			lock ( lockThis ) {
				Brush newBrush = null;
				try {
					switch ( this.BackBrushMode ) {
						case BackgroundBrushMode.Solid:
							newBrush = getBackSolidBrush(this.BackColor);
							break;
						case BackgroundBrushMode.LinearGradient:
							newBrush = getBackLinearGradientBrush(this.GetPaintBounds(), this.BackColor,
										this.BackColor2, this.BackLinearGradientMode);
							break;
						case BackgroundBrushMode.Hatch:
							newBrush = getBackHatchBrush(this.BackHatchStyle, this.BackColor, this.BackColor2);
							break;
						case BackgroundBrushMode.PathGradient:
							newBrush = getBackPathGradientBrush(this.BorderPath, this.BackColor, this.BackColor2);
							break;
						case BackgroundBrushMode.Texture:
							newBrush = getBackTextureBrush(this.BackgroundImage);
							break;
					}
				} catch {
				}
				if ( newBrush != null ) {
					dispose(_backCurrentBrush);
					_backCurrentBrush = newBrush;
				}
			}
		}
		private Brush getBackSolidBrush(Color color)
		{
			return new SolidBrush(color);
		}
		private Brush getBackLinearGradientBrush(Rectangle rect, Color color1, Color color2, LinearGradientMode mode)
		{
			LinearGradientBrush backLinearGradientBrush = new LinearGradientBrush(rect, color1, color2, mode);
			switch ( mode ) {
				case LinearGradientMode.BackwardDiagonal:
				case LinearGradientMode.ForwardDiagonal:
					backLinearGradientBrush.WrapMode = WrapMode.TileFlipXY;
					break;
				case LinearGradientMode.Horizontal:
					backLinearGradientBrush.WrapMode = WrapMode.TileFlipX;
					break;
				case LinearGradientMode.Vertical:
					backLinearGradientBrush.WrapMode = WrapMode.TileFlipY;
					break;
			}
			return backLinearGradientBrush;
		}
		private Brush getBackHatchBrush(HatchStyle hatchstyle, Color color1, Color color2)
		{
			HatchBrush backHatchBrush = new HatchBrush(hatchstyle, color1, color2);
			return backHatchBrush;
		}
		private Brush getBackPathGradientBrush(GraphicsPath path, Color color1, Color color2)
		{
			RectangleF r = path.GetBounds();
			PathGradientBrush backPathGradientBrush = new PathGradientBrush(path);
			backPathGradientBrush.CenterPoint = new PointF(r.X + ( r.Width / 2 ), r.Y + ( r.Height / 2 ));
			backPathGradientBrush.CenterColor = color1;
			backPathGradientBrush.SurroundColors = new Color[] { color2 };
			return backPathGradientBrush;
		}
		private Brush getBackTextureBrush(Image bitmap)
		{
			return getBackSolidBrush(this.BackColor);
		}
		#endregion

		#region Event Handlers
		private void _textbox_TextChanged(object sender, EventArgs e)
		{
			base.Text = _textbox.Text;
		}
		#endregion

		#endregion

		#region Enum: BorderType
		public enum BorderType
		{
			None,
			Rectangle,
			RoundedRectangle,
			DynamicRoundedRectangle,
			Diamond,
			Ellipse,
			TriangleUp,
			TriangleDown,
			TriangleLeft,
			TriangleRight,
			BallonNE,
			BallonNW,
			BallonSW,
			BallonSE,
			SimpleArrowUp,
			SimpleArrowDown,
			SimpleArrowLeft,
			SimpleArrowRight,
			CustomPolygon
		}
		#endregion

		#region Enum: BackgroundBrushMode
		public enum BackgroundBrushMode
		{
			Solid,
			LinearGradient,
			Hatch,
			PathGradient,
			Texture
		}
		#endregion
	}
}
